package edu.cmu.abi;

import edu.cmu.abi.track.hdf5_getters;
import edu.cmu.abi.track.Track;
import java.util.TreeSet;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import ncsa.hdf.object.h5.H5File;
import static java.lang.System.out;

public class Util {

    private static String basePathMSD = "F:/MillionSong/Extracted/";//this is where we hav the million songs
    private static String pathSHS = "D:/ABI Project/SHS";//put the two SHS files here
    private static HashMap<String,String> tracks;
    private static HashMap<String,ArrayList<String>> requiredTracks;
    public static int masterCount=0;
    private static int missingCount=0;
    public static void main(String[] args) throws FileNotFoundException, IOException {
        try {
        	HashMap<String, ArrayList<String>> map = get_all_songs_in_SHS("src/data/shs/");
        	writeToFile("src/data/shs/","map.txt",map);
        	/**
        	String trackID = "TRAAAAW128F429D538.h5";
            String path = "C:/Users/Moha/workspace/HDF5/src/data/";
            Track track = new Track(path, trackID);
            track.loadCharacteristics();
            
            int recordsPerFile = 10000; //increase this to reduce number of output files.
            String destination = "D:/ABI Project/CSV/A";
            char[] alphabet={'A'};
            for(char i:alphabet){
            String pathMSD=basePathMSD+i;
            getAllTracks(pathMSD,pathSHS, destination,recordsPerFile, i);
            }
            getTrackInfo("C:/Users/SimplyYogi/Documents/NetBeansProjects/MSD/trunk/src/data/", "TRAAABD128F429CF47.h5");
        	 * */
        } catch (Exception ex) {
            Logger.getLogger(Util.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    public static HashMap<String,String> getTracks(String pathMSD) {
        File folder = new File(pathMSD);
        File[] listOfFiles = folder.listFiles();
        HashMap<String,String> output = new HashMap<String,String>();
        for (int i = 0; i < folder.listFiles().length; i++) {
            if (listOfFiles[i].isFile()) {
                ++masterCount;
                if((masterCount%1000)==0){
                    out.print(" "+masterCount+" ");
                }
                output.put(listOfFiles[i].getName(), pathMSD);
            } else if (listOfFiles[i].isDirectory()) {
                output.putAll(getTracks(pathMSD+"/"+listOfFiles[i].getName()));
            }
        }
        return output;
    }

    public static String getTrackInfo(String pathMSD,String tid) {
        /*if (!tracks.containsKey(tid)) {
            return "";
        }*/
        if(!tid.endsWith(".h5")){
            tid+=".h5";
        }
        H5File h5 = hdf5_getters.hdf5_open_readonly(pathMSD + "/" + tid);
        int nSongs = hdf5_getters.get_num_songs(h5);

        //System.out.println("numberof songs: " + nSongs + " attributes: ");
        if (nSongs > 1) {
            System.out.println("we'll display infor for song 0");
        }
        ArrayList<String> track = new ArrayList<String>();
        try {
            double[] dub=hdf5_getters.get_segments_timbre(h5);
            System.out.println(dub.length + " " + dub[11]);
            track.add(Integer.toString(hdf5_getters.get_analysis_sample_rate(h5)));
            track.add(hdf5_getters.get_audio_md5(h5));
            track.add(Double.toString(hdf5_getters.get_danceability(h5)));
            track.add(Double.toString(hdf5_getters.get_duration(h5)));
            track.add(Double.toString(hdf5_getters.get_end_of_fade_in(h5)));
            track.add(Double.toString(hdf5_getters.get_energy(h5)));
            track.add(Integer.toString(hdf5_getters.get_key(h5)));
            track.add(Double.toString(hdf5_getters.get_key_confidence(h5)));
            track.add(Double.toString(hdf5_getters.get_loudness(h5)));
            track.add(Integer.toString(hdf5_getters.get_mode(h5)));
            track.add(Double.toString(hdf5_getters.get_mode_confidence(h5)));
            track.add(Double.toString(hdf5_getters.get_start_of_fade_out(h5)));
            track.add(Double.toString(hdf5_getters.get_tempo(h5)));
            track.add(Integer.toString(hdf5_getters.get_time_signature(h5)));
            track.add(Double.toString(hdf5_getters.get_time_signature_confidence(h5)));
            track.add(hdf5_getters.get_track_id(h5));
            track.add(hdf5_getters.get_analyzer_version(h5));
            track.add(Integer.toString(hdf5_getters.get_artist_7digitalid(h5)));
            track.add(Double.toString(hdf5_getters.get_artist_familiarity(h5)));
            track.add(Double.toString(hdf5_getters.get_artist_hotttnesss(h5)));
            track.add(hdf5_getters.get_artist_id(h5));
            track.add(Double.toString(hdf5_getters.get_artist_latitude(h5)));
            //track.add(hdf5_getters.get_location(h5));

            String location = hdf5_getters.get_location(h5);
            if(location.split(",").length>0){
                String s[] =location.split(",");
                location="";
                for(String l:s){
                    location+=l+" ";
                }
            }
            track.add(location);

            track.add(Double.toString(hdf5_getters.get_artist_longitude(h5)));
            track.add(hdf5_getters.get_artist_mbid(h5));
            track.add(hdf5_getters.get_artist_name(h5));
            track.add(Integer.toString(hdf5_getters.get_artist_playmeid(h5)));
            track.add(hdf5_getters.get_genre(h5));
            track.add(hdf5_getters.get_release(h5));
            track.add(Integer.toString(hdf5_getters.get_release_7digitalid(h5)));
            track.add(Double.toString(hdf5_getters.get_song_hotttnesss(h5)));
            track.add(hdf5_getters.get_song_id(h5));
            track.add(hdf5_getters.get_title(h5));
            track.add(Integer.toString(hdf5_getters.get_track_7digitalid(h5)));
            //track.add(Integer.toString(hdf5_getters.get_artist_terms(h5)));
        } catch (Exception e) {
            System.out.println("something went wrong:");
            e.printStackTrace();
            return ",ERROR";
        }
        hdf5_getters.hdf5_close(h5);

        //System.out.println("done, file closed.");
        
        Iterator<String> it = track.iterator();
        StringBuffer sb = new StringBuffer();

        boolean isFirst = true;
        while (it.hasNext()) {
            String temp = it.next();
            if (isFirst) {
                sb.append(temp);
                isFirst = false;
            } else {
                sb.append("," + temp);
            }
        }
        return sb.toString();
    }
    public static String arrayToString (String[] resS){
        boolean isFirst = false;
        String temp="";
        for(String s:resS){
            if(isFirst){
                temp+=s;
            }else{
                temp+=";"+s;
            }
        }
        return temp;
    }
    public static String arrayToString (double[] res){
        boolean isFirst = false;
        String temp="";
        for(double s:res){
            if(isFirst){
                temp+=s;
            }else{
                temp+=";"+s;
            }
        }
        return temp;
    }
    public static String arrayToString (int[] resI){
        boolean isFirst = false;
        String temp="";
        for(int s:resI){
            if(isFirst){
                temp+=s;
            }else{
                temp+=";"+s;
            }
        }
        return temp;
    }

    public static HashMap<String, ArrayList<String>> get_all_songs_in_SHS(String pathSHS) throws FileNotFoundException, IOException {
        //<workId, {trackId1, trackId2, trackId3}
        HashMap<String, ArrayList<String>> coversMap = new HashMap<String, ArrayList<String>>();
        //<workId, trackId
        HashMap<String, String> trackID_work = new HashMap<String, String>();

        TreeSet<String> artists = new TreeSet<String>();

        File folder = new File(pathSHS);
        System.out.println(folder.getPath());
        String[] filesList = folder.list();
        for (String s : filesList) {
            File file = new File(pathSHS + "/" + s);
            if (file.isFile()) {
                out.print("\tReading "+ s +" - ");
                FileReader fr = new FileReader(file);
                BufferedReader br = new BufferedReader(fr);
                String temp = "";

                String clique[] = new String[4];
                String row[] = new String[3];
                int count = 0;
                while (((temp = br.readLine()) != null) || count < 10) {
                    if (temp.length() == 0) {
                        continue;
                    }
                    switch (temp.charAt(0)) {
                        case '#': {
                            continue;
                        }
                        case '%': {
                            clique = temp.split(",");
                            clique[0] = clique[0].substring(1);
                            if (clique.length == 4) {
                                continue;
                            }

                            String r[] = new String[4];
                            switch (clique.length) {
                                case 2:
                                    r[0] = clique[0];
                                    r[3] = clique[1];
                                    clique = r;
                                    continue;
                                case 3:
                                    r[0] = clique[0];
                                    r[1] = clique[1];
                                    r[3] = clique[2];
                                    clique = r;
                                    continue;
                                case 1:
                                    r[0] = clique[0];
                                    clique = r;
                                    continue;
                            }
                        }
                        case 'T': {
                            row = temp.split("<SEP>");
                            String trackId = row[0];
                            String artistId = row[0];
                            String perfId = row[0]; //performanceid or workid same thing

                            trackID_work.put(perfId,trackId);
                            artists.add(artistId);

                            String key = clique[0];
                            ArrayList<String> value = coversMap.get(key);
                            if(value==null){
                                value = new ArrayList<String>();
                                value.add(trackId);
                                coversMap.put(key, value);
                            }else{
                                value.add(trackId);
                            }
                        }
                    }
                    ++count;
                }
                out.print("Done reading: "+count+"\n");
            }
        }
/*
        System.out.println("Starting to change the files1");
        Iterator it = coversMap.keySet().iterator();
        while(it.hasNext()){
            String key = (String) it.next();
            if(key!=null){
                System.out.println("Starting to change the files2");
                String newKey = trackID_work.get(key);
                ArrayList<String> value = coversMap.get(key);
                it.remove();
                coversMap.put(newKey, value);
                System.out.println(newKey);
            }
        }
System.out.println("Starting to change the files3");
 * 
 */
        return coversMap;
    }
    public static void getAllTracks(String pathMSD, String pathSHS, String destinationPath, int recordsPerFile, char alphabet) throws FileNotFoundException, IOException{
        out.println("Starting to write requiredTracks.csv file.");
        requiredTracks=get_all_songs_in_SHS(pathSHS);
        writeToFile(destinationPath,"requiredTracks.csv",requiredTracks);
        out.println("Finished writting requiredTracks.csv file.");

        out.println("-------------------------------------------\n");
        out.println("Loading avaliable tracks from MSD");
        out.print("Files loaded so far: ");
        masterCount=0;
        tracks=getTracks(pathMSD);
        out.print(" - Done reading: "+masterCount+" files.\n");

        
        out.println("-------------------------------------------\n");
        masterCount=0;
        missingCount=0;
        StringBuffer sb = new StringBuffer();
        String header =hdf5_getters.anlaysisSongs+","+hdf5_getters.metadataSongs;
        sb.append(header+"\n");
        Iterator<String> it = requiredTracks.keySet().iterator();
        int countTotal = 0;
        int missing = 0;
        int count=0;
        out.print("Loading batch# "+(countTotal+1)+" (loaded,missing) ");
        while(it.hasNext()){
            String masterFileName = it.next();

            ArrayList<String> tempTracks = requiredTracks.get(masterFileName);
            for(String fileName:tempTracks){
                String path = tracks.get(fileName+".h5");
                if(path!=null){
                    //out.println(fileName);
                    String temp = getTrackInfo(path,fileName+".h5");
                    sb.append(temp).append('\n');
                    ++count;
                }else{
                    ++missing;
                }
            }

        if((count+missing)%10000==0){
                writeToFile(destinationPath, "MSDoutput"+ alphabet+ ++countTotal +".csv",sb, false);
                out.print("("+count+","+missing+")");
                out.print(":=> "+"MSDoutput"+countTotal+".csv\n");
                out.print("Loading batch# "+(countTotal+1)+" (loaded,missing) ");
                masterCount+=count;
                missingCount+=missing;
                sb = new StringBuffer();
        }
            /*if(masterCount%recordsPerFile==0){
                writeToFile(destinationPath, "MSDoutput"+ ++countTotal +".csv",sb);
                out.print("("+count+","+missing+")");
                out.print(":=> "+"MSDoutput"+countTotal+".csv\n");
                out.print("Loading batch# "+(countTotal+1)+" (loaded,missing) ");
                masterCount+=count;
                missingCount+=missing;
                sb = new StringBuffer();
            }*/
        }

        if(sb.length()>=0){
            masterCount+=count;
            missingCount+=missing;
            out.print("("+count+","+missing+")");
            writeToFile(destinationPath, "MSDoutput"+ alphabet+ ++countTotal +".csv",sb, false);
            out.print(":=> "+"MSDoutput"+ alphabet +countTotal+".csv\n");
        }

        out.println("TOTAL (LOADED,MISSING)"+"("+masterCount+","+missingCount+")\n");
    }
    public static void writeToFile(String path, String fileName, StringBuffer sb, boolean append){
        if(!path.endsWith("/")){
            path+="/";
        }
        try{
        // Create file
        FileWriter fstream = new FileWriter(path + fileName, append);
        BufferedWriter out = new BufferedWriter(fstream);
        out.write(sb.toString());
        //Close the output stream
        out.close();
        }catch (Exception e){//Catch exception if any
          System.err.println("Error: " + e.getMessage());
        }        
    }

    public static void writeToFile(String path, String fileName, HashMap<String,ArrayList<String>> contents){
        StringBuffer sb = new StringBuffer();
        Iterator it = contents.keySet().iterator();
        while(it.hasNext()){
            String key = (String) it.next();
            ArrayList<String> values= contents.get(key);
            for(String s:values.toArray(new String[0])){
                sb.append(key+","+s+"\n");
            }
        }
        writeToFile(path,fileName,sb, false);
    }
}
